/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package me.zhengjie.modules.biz.service.impl;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sun.jna.Native;
import me.zhengjie.modules.biz.domain.EntranceGuard;
import me.zhengjie.modules.biz.domain.Lab;
import me.zhengjie.modules.biz.repository.LabRepository;
import me.zhengjie.modules.biz.service.dto.*;
import me.zhengjie.rest.AcsController;
import me.zhengjie.rest.osSelect;
import me.zhengjie.service.HCNetSDK;
import me.zhengjie.utils.ValidationUtil;
import me.zhengjie.utils.FileUtil;
import lombok.RequiredArgsConstructor;
import me.zhengjie.modules.biz.repository.EntranceGuardRepository;
import me.zhengjie.modules.biz.service.EntranceGuardService;
import me.zhengjie.modules.biz.service.mapstruct.EntranceGuardMapper;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import me.zhengjie.utils.PageUtil;
import me.zhengjie.utils.QueryHelp;
import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;



/**
* @website https://eladmin.vip
* @description 服务实现
* @author Admin
* @date 2023-02-18
**/
@Service
@RequiredArgsConstructor
public class EntranceGuardServiceImpl implements EntranceGuardService {

    private final EntranceGuardRepository entranceGuardRepository;
    private final EntranceGuardMapper entranceGuardMapper;
    static HCNetSDK hCNetSDK = null;
    static int lUserID = -1;//用户句柄
    static int iCharEncodeType = 0;//设备字符集
    private final LabRepository labRepository;

    @Override
    public Map<String,Object> queryAll(EntranceGuardQueryCriteria criteria, Pageable pageable){
        Page<EntranceGuard> page = entranceGuardRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        Page<EntranceGuardDto> dto = page.map(entranceGuardMapper::toDto);
        List<EntranceGuardDto> entranceGuardDtoList = dto.getContent();
        for (EntranceGuardDto entranceGuardDto : entranceGuardDtoList) {
            if (entranceGuardDto.getLabId() != null) {
                Lab lab = labRepository.findById(entranceGuardDto.getLabId()).orElseGet(Lab::new);
                if (lab.getId() != null) {
                    entranceGuardDto.setLabName(lab.getName());
                }
            }
        }
        return PageUtil.toPage(dto);
    }

    @Override
    public List<EntranceGuardDto> queryAll(EntranceGuardQueryCriteria criteria){
        List<EntranceGuard> entranceGuardList = entranceGuardRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder));
        List<EntranceGuardDto> entranceGuardDtoList = entranceGuardMapper.toDto(entranceGuardList);
        for (EntranceGuardDto entranceGuardDto : entranceGuardDtoList) {
            if (entranceGuardDto.getLabId() != null) {
                Lab lab = labRepository.findById(entranceGuardDto.getLabId()).orElseGet(Lab::new);
                if (lab.getId() != null) {
                    entranceGuardDto.setLabName(lab.getName());
                }
            }
        }
        return entranceGuardDtoList;
    }

    @Override
    @Transactional
    public EntranceGuardDto findById(Integer id) {
        EntranceGuard entranceGuard = entranceGuardRepository.findById(id).orElseGet(EntranceGuard::new);
        ValidationUtil.isNull(entranceGuard.getId(),"EntranceGuard","id",id);
        return entranceGuardMapper.toDto(entranceGuard);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public EntranceGuardDto create(EntranceGuard resources) {
        return entranceGuardMapper.toDto(entranceGuardRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(EntranceGuard resources) {
        EntranceGuard entranceGuard = entranceGuardRepository.findById(resources.getId()).orElseGet(EntranceGuard::new);
        ValidationUtil.isNull( entranceGuard.getId(),"EntranceGuard","id",resources.getId());
        entranceGuard.copy(resources);
        entranceGuardRepository.save(entranceGuard);
    }

    @Override
    public void deleteAll(Integer[] ids) {
        for (Integer id : ids) {
            entranceGuardRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<EntranceGuardDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (EntranceGuardDto entranceGuard : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("ip地址", entranceGuard.getIp());
            map.put("编号", entranceGuard.getNo());
            map.put("实验室", entranceGuard.getLabName());
            map.put("备注", entranceGuard.getNote());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public void addList() {
      //  /api/resource/v2/acsDevice/search
    }

    @Override
    public Object list() {
        ///api/resource/v2/acsDevice/search


//        JSONObject object= JSONObject.parseObject(s);
//        EntranceGuardList entranceGuardList = JSON.parseObject(String.valueOf(object), EntranceGuardList.class);
//        System.out.println(entranceGuardList);
//            List<EntanceGuard> entanceGuardList = new ArrayList<>();
//            EntanceGuard [] entanceGuards = entranceGuardList.getData().getList();
//            Collections.addAll(entanceGuardList,entanceGuards);
//            List<EntranceGuard> entranceGuards = entranceGuardRepository.findAll();
//        System.out.println(entranceGuards);
//            for (EntanceGuard entanceGuard:entanceGuardList) {
//                int count = 0;
//                for (EntranceGuard entranceGuard:entranceGuards){
//                    if (!Objects.equals(entanceGuard.getIndexCode(), entranceGuard.getIndexCode())){
//                        count++;
//                    }
//                }
//                if (count==entranceGuards.size()){
//                    EntranceGuard entranceGuard = new EntranceGuard();
//                    entranceGuard.setIndexCode(entanceGuard.getIndexCode());
//                    entranceGuard.setResourceType(entanceGuard.getResourceType());
//                    entranceGuard.setDevSerialNum(entanceGuard.getDevSerialNum());
//                    entranceGuard.setPort(entanceGuard.getPort());
//                    entranceGuard.setRegionIndexCode(entanceGuard.getRegionIndexCode());
//                    entranceGuard.setName(entanceGuard.getName());
//                    entranceGuard.setIp(entanceGuard.getIp());
//                    entranceGuardRepository.save(entranceGuard);
//                }
//            }
            //            Map map = new HashMap();
//            String[] list = {"name", "nickname", "wx_union_id", "wx_open_id", "wx_app_open_id", "wx_avatar"};
//            map.put("field_list", list);
//            postData.put("data", map);
//            ResultMap resultMap = restTemplate.postForEntity(url, postData, ResultMap.class).getBody();
//            if (resultMap.get("code").equals(0)) {
//                String data = JSON.toJSONString(resultMap.get("data"));
//                user = JSONObject.parseObject(data, XiaoETongUser.class);
//            }





        RestTemplate restTemplate = new RestTemplate();
        try {

            HttpHeaders headers = new HttpHeaders();
            String url = "https:/api/resource/v2/acsDevice/search";
            JSONObject postData = new JSONObject();
            postData.put("pageNo", 1);
            postData.put("pageSize", 10000);
            String jsonString = JSONObject.toJSONString(postData);
            HttpEntity<String> entity = new HttpEntity<>(jsonString, headers);
            ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, entity, String.class);
            String entityBody = responseEntity.getBody();
            String jsonObject = JSON.toJSONString(entityBody);
            EntranceGuardList entranceGuardList = JSON.parseObject(jsonObject, EntranceGuardList.class);
            List<EntanceGuard> entanceGuardList = new ArrayList<>();
            EntanceGuard [] entanceGuards =  entranceGuardList.getData().getList();
            Collections.addAll(entanceGuardList,entanceGuards);
            List<EntranceGuard> entranceGuards = entranceGuardRepository.findAll();

            for (EntanceGuard entanceGuard:entanceGuardList) {
//                int count = 0;
//                for (EntranceGuard entranceGuard:entranceGuards){
//                    if (!Objects.equals(entanceGuard.getIndexCode(), entranceGuard.getIndexCode())){
//                        count++;
//                    }
//                }
                EntranceGuard e = entranceGuardRepository.findByIndexCode(entanceGuard.getIndexCode());
                if (e==null){
                    EntranceGuard entranceGuard = new EntranceGuard();
                    entranceGuard.setIndexCode(entanceGuard.getIndexCode());
                    entranceGuard.setResourceType(entanceGuard.getResourceType());
                    entranceGuard.setDevSerialNum(entanceGuard.getDevSerialNum());
                    entranceGuard.setPort(entanceGuard.getPort());
                    entranceGuard.setRegionIndexCode(entanceGuard.getRegionIndexCode());
                    entranceGuard.setName(entanceGuard.getName());
                    entranceGuard.setIp(entanceGuard.getIp());
                    entranceGuard.setIsOpen(0);
                    entranceGuardRepository.save(entranceGuard);
                }
            }
            //            Map map = new HashMap();
//            String[] list = {"name", "nickname", "wx_union_id", "wx_open_id", "wx_app_open_id", "wx_avatar"};
//            map.put("field_list", list);
//            postData.put("data", map);
//            ResultMap resultMap = restTemplate.postForEntity(url, postData, ResultMap.class).getBody();
//            if (resultMap.get("code").equals(0)) {
//                String data = JSON.toJSONString(resultMap.get("data"));
//                user = JSONObject.parseObject(data, XiaoETongUser.class);
//            }
        } catch (Exception e) {
            e.printStackTrace();
        }



        return null;
    }

    @Override
    public void doControl(int id,int state) {
      //  /api/acs/v1/door/doControl
        EntranceGuard entranceGuard = entranceGuardRepository.findById(id).orElseGet(EntranceGuard::new);

        state = state==1?2:1;
        entranceGuard.setIsOpen(state);

//        entranceGuardRepository.save(entranceGuard);
//        String [] indexCodes = new String[1];
//        indexCodes[0] = entranceGuard.getIndexCode();
//        RestTemplate restTemplate = new RestTemplate();
//        try {
//            //控制开关门
//            HttpHeaders headers = new HttpHeaders();
//            String url = "https:/api/acs/v1/door/doControl";
//            JSONObject postData = new JSONObject();
//            postData.put("doorIndexCodes", indexCodes);
//            state = state==1?2:1;
//            postData.put("controlType", state);
//            String jsonString = JSONObject.toJSONString(postData);
//            HttpEntity<String> entity = new HttpEntity<>(jsonString, headers);
//            ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, entity, String.class);
//            String entityBody = responseEntity.getBody();
//            String jsonObject = JSON.toJSONString(entityBody);
//            ControlDto controlDto = JSON.parseObject(jsonObject, ControlDto.class);
//
//
//            //查看门状态
//            HttpHeaders headersState = new HttpHeaders();
//            String urlState = "https:/api/acs/v1/door/states";
//            JSONObject postDataState = new JSONObject();
//            postData.put("doorIndexCodes", indexCodes);
//            String jsonStringState = JSONObject.toJSONString(postDataState);
//            HttpEntity<String> entityState = new HttpEntity<>(jsonStringState, headersState);
//            ResponseEntity<String> responseEntityState = restTemplate.postForEntity(urlState, entityState, String.class);
//            String entityBodyState = responseEntityState.getBody();
//            String jsonObjectState = JSON.toJSONString(entityBodyState);
//            StateDto stateDto = JSON.parseObject(jsonObjectState, StateDto.class);
//            StateDataDto stateDataDto = (StateDataDto) stateDto.getData();
//            List<AuthDoorDto> authDoorDtoList = new ArrayList<>();
//            AuthDoorDto [] authDoorDtos = stateDataDto.getAuthDoorList();
//            Collections.addAll(authDoorDtoList,authDoorDtos);
//            for (AuthDoorDto authDoorDto:authDoorDtoList) {
//                if (authDoorDto.getDoorIndexCode().equals(indexCodes[0])){
//                    entranceGuard.setIsOpen(authDoorDto.getDoorState());
//                    entranceGuardRepository.save(entranceGuard);
//                }
//            }
//
//
//        }catch (Exception e) {
//            e.printStackTrace();
//        }
    }

    @Override
    public void states() {
        ///api/acs/v1/door/states
    }

    @Override
    public ArrayList<Map<String, Object>> listFloor(Integer floor) {
        ArrayList<Map<String,Object>> arrayList = new ArrayList<>();
        List<EntranceGuard> entranceGuardList = entranceGuardRepository.findByFloor(floor);
        for (EntranceGuard entranceGuard : entranceGuardList) {
            Map<String,Object> hashMap = new HashMap<>();
            hashMap.put("position",entranceGuard.getCoordinate().replace("[","").replace("]","").split(","));
            hashMap.put("is_open",entranceGuard.getIsOpen());
            arrayList.add(hashMap);
        }
        return arrayList;
    }

    @Override
    public List<Map<String, Object>> getCountByFloor() {
        return entranceGuardRepository.getCountByFloor();
    }

    @Override
    public void control(Integer id, Integer state) {

        if(hCNetSDK == null)
        {
            if(!createSDKInstance())
            {
                System.out.println("Load SDK fail");
                return;
            }
        }
        //linux系统建议调用以下接口加载组件库
        if (osSelect.isLinux())
        {
            HCNetSDK.BYTE_ARRAY ptrByteArray1 = new HCNetSDK.BYTE_ARRAY(256);
            HCNetSDK.BYTE_ARRAY ptrByteArray2 = new HCNetSDK.BYTE_ARRAY(256);
            //这里是库的绝对路径，请根据实际情况修改，注意改路径必须有访问权限
            String strPath1 = System.getProperty("user.dir") + "/lib/libcrypto.so.1.1";
            String strPath2 = System.getProperty("user.dir") + "/lib/libssl.so.1.1";

            System.arraycopy(strPath1.getBytes(), 0, ptrByteArray1.byValue, 0, strPath1.length());
            ptrByteArray1.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(3, ptrByteArray1.getPointer());

            System.arraycopy(strPath2.getBytes(), 0, ptrByteArray2.byValue, 0, strPath2.length());
            ptrByteArray2.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(4, ptrByteArray2.getPointer());

            String strPathCom = System.getProperty("user.dir") + "/lib/";
            HCNetSDK.NET_DVR_LOCAL_SDK_PATH struComPath = new HCNetSDK.NET_DVR_LOCAL_SDK_PATH();
            System.arraycopy(strPathCom.getBytes(), 0, struComPath.sPath, 0, strPathCom.length());
            struComPath.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(2, struComPath.getPointer());
        }

        hCNetSDK.NET_DVR_Init();
        //开启SDK日志打印
        boolean i= hCNetSDK.NET_DVR_SetLogToFile(3, "./sdklog", false);

        EntranceGuard entranceGuard = entranceGuardRepository.findById(id).orElseGet(EntranceGuard::new);
        ValidationUtil.isNull( entranceGuard.getId(),"EntranceGuard","id",entranceGuard.getId());

        login_V40(entranceGuard.getIp(), entranceGuard.getAccount(), entranceGuard.getPassword(), Convert.toShort(entranceGuard.getPort()));	//登录设备

        //远程控门
        // int lGatewayIndex = 1; 门禁序号（楼层编号、锁ID），从1开始，-1表示对所有门（或者梯控的所有楼层）进行操作
        // int dwStaic = 1; 命令值：0 - 关闭（对于梯控，表示受控），1 - 打开（对于梯控，表示开门），
        //2 - 常开（对于梯控，表示自由、通道状态），3 - 常关（对于梯控，表示禁用），
        //4 - 恢复（梯控，普通状态），5 - 访客呼梯（梯控），6 - 住户呼梯（梯控）

        if (!hCNetSDK.NET_DVR_ControlGateway(lUserID, 1, state))
        {
            System.out.println("NET_DVR_ControlGateway failed, error code: %d\n" + hCNetSDK.NET_DVR_GetLastError());
        }
        else
        {
//            System.out.println("NET_DVR_ControlGateway successfully!\n");
            entranceGuard.setIsOpen(state);
            update(entranceGuard);
        }

        logout();

        //释放SDK，程序退出前调用
        hCNetSDK.NET_DVR_Cleanup();
    }

    /**
     * 根据不同操作系统选择不同的库文件和库路径
     * @return
     */
    private static boolean createSDKInstance()
    {
        if(hCNetSDK == null)
        {
            synchronized (HCNetSDK.class)
            {
                String strDllPath = "";
                try
                {
                    //System.setProperty("jna.debug_load", "true");
                    if(osSelect.isWindows())
                        //win系统加载库路径
                        strDllPath = System.getProperty("user.dir") + "\\eladmin-tools\\src\\main\\java\\me\\zhengjie\\config\\HK\\HCNetSDK.dll";
                    else if(osSelect.isLinux())
                        //Linux系统加载库路径
                        strDllPath =  System.getProperty("user.dir") + "/lib/libhcnetsdk.so";
                    hCNetSDK = (HCNetSDK) Native.loadLibrary(strDllPath, HCNetSDK.class);
                }catch (Exception ex) {
                    System.out.println("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 设备登录
     * @param ipadress IP地址
     * @param user  用户名
     * @param psw  密码
     * @param port 端口，默认8000
     */
    public static void login_V40(String ipadress, String user, String psw, short port) {
        //注册
        HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();//设备登录信息
        String m_sDeviceIP = ipadress;//设备ip地址
        m_strLoginInfo.sDeviceAddress = new byte[HCNetSDK.NET_DVR_DEV_ADDRESS_MAX_LEN];
        System.arraycopy(m_sDeviceIP.getBytes(), 0, m_strLoginInfo.sDeviceAddress, 0, m_sDeviceIP.length());
        String m_sUsername = user;//设备用户名
        m_strLoginInfo.sUserName = new byte[HCNetSDK.NET_DVR_LOGIN_USERNAME_MAX_LEN];
        System.arraycopy(m_sUsername.getBytes(), 0, m_strLoginInfo.sUserName, 0, m_sUsername.length());
        String m_sPassword = psw;//设备密码
        m_strLoginInfo.sPassword = new byte[HCNetSDK.NET_DVR_LOGIN_PASSWD_MAX_LEN];
        System.arraycopy(m_sPassword.getBytes(), 0, m_strLoginInfo.sPassword, 0, m_sPassword.length());
        m_strLoginInfo.wPort = port; //sdk端口
        m_strLoginInfo.bUseAsynLogin = false; //是否异步登录：0- 否，1- 是
		m_strLoginInfo.write();
        HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();//设备信息
        lUserID = hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);
        if (lUserID == -1) {
            System.out.println("登录失败，错误码为" + hCNetSDK.NET_DVR_GetLastError());
        } else {
            System.out.println("登录成功！");
            m_strDeviceInfo.read();
            iCharEncodeType = m_strDeviceInfo.byCharEncodeType;
        }
    }

    /**
     * 登出操作
     *
     */
    public static void logout() {
        /**登出和清理，释放SDK资源*/
        if (lUserID >= 0) {
            if (!hCNetSDK.NET_DVR_Logout(lUserID)) {
                System.out.println("设备注销失败，错误码：" + hCNetSDK.NET_DVR_GetLastError());
                return;
            }
            System.out.println("设备注销成功！！！");
        }
    }
}
